<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>管理后台</title>
    <script src="js/vue.global.prod.js"></script>
    <script src="js/axios.min.js"></script>
    <link rel="stylesheet" href="js/github.min.css" />
    <style>
        body {
            font-family: 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', Arial, sans-serif;
            background: #f5f7fa;
            margin: 0;
            padding: 0;
        }
        #app {
            display: flex;
            height: 100vh;
        }
        .sidebar {
            width: 200px;
            background: #1976d2;
            color: #fff;
            display: flex;
            flex-direction: column;
            padding: 32px 0 0 0;
        }
        .menu-item {
            padding: 16px 32px;
            cursor: pointer;
            font-size: 17px;
            transition: background 0.2s;
        }
        .menu-item.active, .menu-item:hover {
            background: #1565c0;
        }
        .main {
            flex: 1;
            background: #fff;
            padding: 36px 48px;
            overflow-y: auto;
        }
        h2 {
            color: #1976d2;
            margin-top: 0;
        }
        .table {
            width: 100%;
            border-collapse: collapse;
            margin-bottom: 24px;
        }
        .table th, .table td {
            border: 1px solid #e3e8f0;
            padding: 10px 14px;
            text-align: left;
        }
        .table th {
            background: #f3f6fd;
        }
        .actions button {
            margin-right: 8px;
            padding: 4px 14px;
            border: none;
            border-radius: 4px;
            background: #1976d2;
            color: #fff;
            cursor: pointer;
            font-size: 14px;
        }
        .actions button:last-child {
            margin-right: 0;
        }
        .actions button.delete {
            background: #d32f2f;
        }
        .actions button.add {
            background: #388e3c;
        }
        .form-row {
            display: flex;
            gap: 12px;
            margin-bottom: 18px;
        }
        .form-row input {
            padding: 8px 12px;
            border-radius: 4px;
            border: 1px solid #b3c6e0;
            font-size: 15px;
        }
        .form-row button {
            padding: 8px 18px;
            border-radius: 4px;
            border: none;
            background: #1976d2;
            color: #fff;
            font-size: 15px;
            cursor: pointer;
        }
        .server-list {
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
            margin-top: 6px;
        }
        .server-tag {
            background: #e3f2fd;
            color: #1976d2;
            border-radius: 3px;
            padding: 3px 10px;
            font-size: 14px;
            margin-right: 4px;
            margin-bottom: 4px;
            display: flex;
            align-items: center;
        }
        .server-tag .remove {
            margin-left: 6px;
            color: #d32f2f;
            cursor: pointer;
            font-size: 15px;
        }
        .modal-mask {
            position: fixed;
            z-index: 1000;
            left: 0; top: 0; right: 0; bottom: 0;
            background: rgba(0,0,0,0.18);
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .modal-box {
            background: #fff;
            border-radius: 10px;
            box-shadow: 0 4px 32px #0002;
            padding: 28px 32px 18px 32px;
            min-width: 320px;
            max-width: 90vw;
            width: 400px;
            display: flex;
            flex-direction: column;
            align-items: stretch;
        }
        .modal-box h3 {
            margin-top: 0;
            color: #1976d2;
            margin-bottom: 18px;
            text-align: center;
        }
        .login-btn, .logout-btn {
            padding: 6px 18px;
            border-radius: 6px;
            border: none;
            background: linear-gradient(135deg, #1976d2 60%, #42a5f5 100%);
            color: #fff;
            font-size: 15px;
            font-weight: 600;
            cursor: pointer;
            box-shadow: 0 1px 4px #0001;
            transition: background 0.2s, box-shadow 0.2s;
        }
        .login-btn:hover, .logout-btn:hover {
            background: linear-gradient(135deg, #1565c0 60%, #1976d2 100%);
        }
        .auth-modal {
            position: fixed;
            z-index: 1000;
            left: 0; top: 0; right: 0; bottom: 0;
            background: rgba(0,0,0,0.18);
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .auth-box {
            position: relative;
            background: #fff;
            border-radius: 12px;
            box-shadow: 0 4px 32px #0002;
            padding: 36px 32px 28px 32px;
            min-width: 320px;
            max-width: 90vw;
            width: 350px;
            display: flex;
            flex-direction: column;
            align-items: stretch;
        }
        .auth-box h2 {
            text-align: center;
            margin-bottom: 18px;
            color: #1976d2;
        }
        .auth-box form {
            display: flex;
            flex-direction: column;
            gap: 12px;
            margin-bottom: 8px;
        }
        .auth-box input {
            padding: 10px 12px;
            border-radius: 6px;
            border: 1.2px solid #b3c6e0;
            font-size: 16px;
        }
        .auth-box button {
            padding: 10px 0;
            border-radius: 6px;
            border: none;
            background: linear-gradient(135deg, #1976d2 60%, #42a5f5 100%);
            color: #fff;
            font-size: 16px;
            font-weight: 600;
            cursor: pointer;
            margin-bottom: 8px;
        }
        .auth-box button:disabled {
            background: #b3c6e0;
            color: #fff;
            cursor: not-allowed;
        }
        .auth-error {
            color: #d32f2f;
            text-align: center;
            margin-top: 8px;
            font-size: 15px;
        }
        .auth-close {
            position: absolute;
            top: 12px;
            right: 16px;
            background: none;
            border: none;
            font-size: 26px;
            color: #888;
            cursor: pointer;
            z-index: 10;
            transition: color 0.2s;
        }
        .auth-close:hover {
            color: #1976d2;
        }
        .server-list-panel {
            border: 1.5px solid #e3e8f0;
            border-radius: 7px;
            min-height: 180px;
            background: #fafdff;
            padding: 8px 0;
            max-height: 260px;
            overflow-y: auto;
        }
        .server-item {
            padding: 8px 16px;
            margin: 4px 8px;
            border-radius: 5px;
            cursor: pointer;
            transition: background 0.18s;
            font-size: 15px;
        }
        .server-item.selected {
            background: #e3f2fd;
            color: #1976d2;
            font-weight: 600;
            border: 1.5px solid #1976d2;
        }
        .server-item:hover {
            background: #f0f7ff;
        }
        .server-empty {
            color: #bbb;
            text-align: center;
            margin: 18px 0;
            font-size: 15px;
        }
        .arrow-btn {
            width: 38px;
            height: 38px;
            border-radius: 50%;
            border: none;
            background: linear-gradient(135deg, #1976d2 60%, #42a5f5 100%);
            color: #fff;
            font-size: 20px;
            font-weight: bold;
            cursor: pointer;
            box-shadow: 0 1px 4px #0001;
            transition: background 0.2s, box-shadow 0.2s;
        }
        .arrow-btn:disabled {
            background: #b3c6e0;
            color: #fff;
            cursor: not-allowed;
        }
        .arrow-btn:not(:disabled):hover {
            background: linear-gradient(135deg, #1565c0 60%, #1976d2 100%);
        }
        .add-domain-btn {
            padding: 10px 32px;
            border-radius: 8px;
            border: none;
            background: linear-gradient(135deg, #1976d2 60%, #42a5f5 100%);
            color: #fff;
            font-size: 17px;
            font-weight: 700;
            cursor: pointer;
            box-shadow: 0 2px 8px #1976d233;
            margin-bottom: 18px;
            transition: background 0.2s, box-shadow 0.2s;
        }
        .add-domain-btn:hover {
            background: linear-gradient(135deg, #1565c0 60%, #1976d2 100%);
            box-shadow: 0 4px 16px #1976d244;
        }
    </style>
</head>
<body>
<div id="app">
    <div v-if="!isLoggedIn" style="width:100vw;height:100vh;display:flex;align-items:center;justify-content:center;background:#f5f7fa;">
        <button class="login-btn" @click="showLoginModal=true">登录</button>
    </div>
    <div v-else style="width:100vw;height:100vh;display:flex;flex-direction:column;">
        <div style="height:48px;display:flex;align-items:center;justify-content:flex-end;padding:0 36px;background:#f3f6fd;border-bottom:1px solid #e3e8f0;">
            <span style="color:#1976d2;font-size:16px;font-weight:600;">{{ userInfo }}</span>
            <button class="logout-btn" style="margin-left:18px;" @click="logout">退出</button>
        </div>
        <div style="flex:1;display:flex;min-height:0;">
            <div class="sidebar">
                <div :class="['menu-item', {active: menu==='domain'}]" @click="menu='domain'">领域管理</div>
                <div :class="['menu-item', {active: menu==='server'}]" @click="menu='server'">服务器管理</div>
            </div>
            <div class="main">
                <div v-if="menu==='domain'">
                    <h2>领域管理</h2>
                    <button class="add-domain-btn" @click="showAddDomainDialog=true">＋ 添加领域</button>
                    <table class="table">
                        <thead>
                        <tr><th>名称</th><th>描述</th><th>操作</th></tr>
                        </thead>
                        <tbody>
                        <tr v-for="d in domains" :key="d.id">
                            <td>{{ d.name }}</td>
                            <td>{{ d.description }}</td>
                            <td class="actions">
                                <button @click="editDomain(d)">编辑</button>
                                <button class="delete" @click="deleteDomain(d.id)">删除</button>
                            </td>
                        </tr>
                        </tbody>
                    </table>
                    <div v-if="showAddDomainDialog" class="modal-mask">
                        <div class="modal-box">
                            <h3>添加领域</h3>
                            <div class="form-row" style="flex-direction:column;align-items:stretch;gap:8px;">
                                <input v-model="newDomain.id" placeholder="领域ID" />
                                <input v-model="newDomain.name" placeholder="领域名称" />
                                <input v-model="newDomain.description" placeholder="描述" />
                            </div>
                            <div style="text-align:right;">
                                <button @click="addDomainDialog">确定</button>
                                <button style="margin-left:10px;" @click="showAddDomainDialog=false">取消</button>
                            </div>
                        </div>
                    </div>
                    <div v-if="editDomainDialog.visible" class="modal-mask">
                        <div class="modal-box" style="width:650px;">
                            <h3 style="margin-bottom:24px;">编辑领域</h3>
                            <div style="display:flex;gap:32px;">
                                <!-- 未关联服务器 -->
                                <div style="flex:1;">
                                    <div style="font-weight:600;margin-bottom:10px;">可添加服务器</div>
                                    <div class="server-list-panel">
                                        <div v-for="s in unlinkedServers" :key="s.id"
                                             @click="selectLeft(s)"
                                             :class="['server-item', {selected: selectedLeft?.id===s.id}]">
                                            {{ s.name }}
                                        </div>
                                        <div v-if="unlinkedServers.length===0" class="server-empty">无</div>
                                    </div>
                                </div>
                                <!-- 按钮 -->
                                <div style="display:flex;flex-direction:column;justify-content:center;gap:18px;">
                                    <button class="arrow-btn" @click="addServerToDomainEdit" :disabled="!selectedLeft">→</button>
                                    <button class="arrow-btn" @click="removeServerFromDomainEdit" :disabled="!selectedRight">←</button>
                                </div>
                                <!-- 已关联服务器 -->
                                <div style="flex:1;">
                                    <div style="font-weight:600;margin-bottom:10px;">已关联服务器</div>
                                    <div class="server-list-panel">
                                        <div v-for="s in linkedServers" :key="s.id"
                                             @click="selectRight(s)"
                                             :class="['server-item', {selected: selectedRight?.id===s.id}]">
                                            {{ s.name }}
                                        </div>
                                        <div v-if="linkedServers.length===0" class="server-empty">无</div>
                                    </div>
                                </div>
                            </div>
                            <div style="text-align:right;margin-top:24px;">
                                <button @click="editDomainDialog.visible=false">关闭</button>
                            </div>
                        </div>
                    </div>
                </div>
                <div v-else>
                    <h2>服务器管理</h2>
                    <button class="add-domain-btn" @click="showAddServerDialog=true">＋ 添加服务器</button>
                    <table class="table">
                        <thead>
                        <tr><th>名称</th><th>描述</th><th>配置</th><th>操作</th></tr>
                        </thead>
                        <tbody>
                        <tr v-for="s in servers" :key="s.id">
                            <td>{{ s.name }}</td>
                            <td>{{ s.description }}</td>
                            <td><pre style="max-width:300px;overflow:auto">{{ s.config }}</pre></td>
                            <td class="actions">
                                <button @click="editServer(s)">编辑</button>
                                <button class="delete" @click="deleteServer(s.id)">删除</button>
                            </td>
                        </tr>
                        </tbody>
                    </table>
                    <div v-if="showAddServerDialog" class="modal-mask">
                        <div class="modal-box">
                            <h3>添加服务器</h3>
                            <div class="form-row" style="flex-direction:column;align-items:stretch;gap:8px;">
                                <input v-model="newServer.name" placeholder="服务器名称" />
                                <input v-model="newServer.description" placeholder="描述" />
                                <label style="font-size:15px;color:#1976d2;margin-bottom:4px;">配置(JSON)</label>
                                <textarea v-model="newServer.config" placeholder="请输入JSON配置" rows="8" style="resize:vertical;width:100%;font-size:15px;padding:8px 12px;border-radius:4px;border:1px solid #b3c6e0;"></textarea>
                            </div>
                            <div style="text-align:right;">
                                <button @click="addServerDialog">确定</button>
                                <button style="margin-left:10px;" @click="showAddServerDialog=false">取消</button>
                            </div>
                        </div>
                    </div>
                    <div v-if="editServerDialog.visible" class="modal-mask">
                        <div class="modal-box">
                            <h3>编辑服务器</h3>
                            <div class="form-row" style="flex-direction:column;align-items:stretch;gap:8px;">
                                <input v-model="editServerDialog.server.id" placeholder="服务器ID" disabled />
                                <input v-model="editServerDialog.server.name" placeholder="服务器名称" />
                                <input v-model="editServerDialog.server.description" placeholder="描述" />
                                <label style="font-size:15px;color:#1976d2;margin-bottom:4px;">配置(JSON)</label>
                                <textarea v-model="editServerDialog.server.config" placeholder="请输入JSON配置" rows="8" style="resize:vertical;width:100%;font-size:15px;padding:8px 12px;border-radius:4px;border:1px solid #b3c6e0;"></textarea>
                            </div>
                            <div style="text-align:right;">
                                <button @click="saveEditServer">确定</button>
                                <button style="margin-left:10px;" @click="editServerDialog.visible=false">取消</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div v-if="showLoginModal" class="auth-modal">
        <div class="auth-box">
            <button class="auth-close" @click="showLoginModal=false" title="关闭">×</button>
            <h2>登录</h2>
            <form @submit.prevent="doLogin">
                <input v-model="authForm.username" placeholder="用户名" required autocomplete="username" />
                <div style="position:relative;display:flex;align-items:center;">
                    <input :type="showPassword ? 'text' : 'password'" v-model="authForm.password" placeholder="密码" required autocomplete="current-password" style="flex:1;" />
                    <span @click="showPassword=!showPassword" style="position:absolute;right:10px;cursor:pointer;font-size:18px;color:#888;user-select:none;">
                        {{ showPassword ? '🙈' : '👁️' }}
                    </span>
                </div>
                <button type="submit" :disabled="authLoading">登录</button>
            </form>
            <div v-if="authError" class="auth-error">{{ authError }}</div>
        </div>
    </div>
</div>
<script>
const { createApp, ref, reactive } = Vue;
createApp({
    setup() {
        const isLoggedIn = ref(localStorage.getItem('isLoggedIn') === '1');
        const userInfo = ref(localStorage.getItem('username') || '');
        const showLoginModal = ref(false);
        const authForm = reactive({ username: '', password: '' });
        const authLoading = ref(false);
        const authError = ref('');
        const menu = ref('domain');
        const domains = ref([]);
        const servers = ref([]);
        const domainServers = ref([]); // 关系表
        const newDomain = reactive({ id: '', name: '', description: '' });
        const newServer = reactive({ name: '', description: '', config: '' });
        const selectedServer = reactive({});
        const showAddServerDialog = ref(false);
        const showPassword = ref(false);
        const editDomainDialog = reactive({ visible: false, domain: null });
        const linkedServers = ref([]);
        const unlinkedServers = ref([]);
        const selectedLeft = ref(null);
        const selectedRight = ref(null);
        const showAddDomainDialog = ref(false);
        const editServerDialog = reactive({ visible: false, server: { id: '', name: '', description: '', config: '' } });

        // 加载数据
        const fetchAll = async () => {
            const [dRes, sRes] = await Promise.all([
                axios.get('/domain/list'),
                axios.get('/server/list'),
                //axios.get('/domainservers')
            ]);
            domains.value = dRes.data;
            servers.value = sRes.data;

        };

        // 登录逻辑
        const doLogin = async () => {
            authLoading.value = true;
            try {
                const res = await axios.post('/login', null, {
                    params: {
                        username: authForm.username,
                        password: authForm.password
                    }
                });
                userInfo.value = res.data.username;
                isLoggedIn.value = true;
                localStorage.setItem('isLoggedIn', '1');
                localStorage.setItem('username', res.data.username);
                showLoginModal.value = false;
                authForm.username = '';
                authForm.password = '';
                authError.value = '';
                await fetchAll();
            } catch (err) {
                authError.value = err.response?.data || '登录失败，请检查用户名和密码';
            } finally {
                authLoading.value = false;
            }
        };
        const logout = async () => {
            try {
                await axios.post('/logout');
            } catch {}
            isLoggedIn.value = false;
            userInfo.value = '';
            localStorage.removeItem('isLoggedIn');
            localStorage.removeItem('username');
            location.reload();
        };
        // 检查登录状态
        const checkLogin = async () => {
            try {
                const res = await axios.get('/me');
                userInfo.value = res.data.username;
                isLoggedIn.value = true;
                localStorage.setItem('isLoggedIn', '1');
                localStorage.setItem('username', res.data.username);
                await fetchAll();
            } catch {
                isLoggedIn.value = false;
                userInfo.value = '';
                localStorage.removeItem('isLoggedIn');
                localStorage.removeItem('username');
            }
        };
        checkLogin();

        // 领域管理
        const addDomainDialog = async () => {
            if (!newDomain.id || !newDomain.name) return;
            await axios.post('/domain/create', newDomain);
            newDomain.id = '';
            newDomain.name = '';
            newDomain.description = '';
            showAddDomainDialog.value = false;
            await fetchAll();
        };
        const editDomain = async (d) => {
            editDomainDialog.domain = d;
            editDomainDialog.visible = true;
            await loadDomainServers(d.id);
        };
        const deleteDomain = async (id) => {
            if (confirm('确定删除该领域？')) {
                await axios.post('/domain/delete', null, { params: { id } });
                await fetchAll();
            }
        };
        const loadDomainServers = async (domainId) => {
            const res = await axios.get('/domain/servers', { params: { domainId } });
            linkedServers.value = res.data;
            unlinkedServers.value = servers.value.filter(s => !linkedServers.value.some(ls => ls.id === s.id));
            selectedLeft.value = null;
            selectedRight.value = null;
        };
        const selectLeft = (s) => { selectedLeft.value = s; };
        const selectRight = (s) => { selectedRight.value = s; };
        const addServerToDomainEdit = async () => {
            if (!selectedLeft.value) return;
            await axios.post('/domain/addServer', null, { params: { domainId: editDomainDialog.domain.id, serverId: selectedLeft.value.id } });
            await loadDomainServers(editDomainDialog.domain.id);
        };
        const removeServerFromDomainEdit = async () => {
            if (!selectedRight.value) return;
            await axios.post('/domain/removeServer', null, { params: { domainId: editDomainDialog.domain.id, serverId: selectedRight.value.id } });
            await loadDomainServers(editDomainDialog.domain.id);
        };
        // 服务器管理
        const addServerDialog = async () => {
            if (!newServer.name) return;
            await axios.post('/server/create', newServer);
            newServer.name = '';
            newServer.description = '';
            newServer.config = '';
            showAddServerDialog.value = false;
            await fetchAll();
        };
        const editServer = (s) => {
            editServerDialog.server = { ...s };
            editServerDialog.visible = true;
        };
        const saveEditServer = async () => {
            await axios.post('/server/update', editServerDialog.server);
            editServerDialog.visible = false;
            await fetchAll();
        };
        const deleteServer = async (id) => {
            if (confirm('确定删除该服务器？')) {
                await axios.post('/server/delete', null, { params: { id } });
                await fetchAll();
            }
        };
        // 关系管理
        const getServersOfDomain = (domainId) => {
            const rels = domainServers.value.filter(ds => ds.domainId === domainId);
            return servers.value.filter(s => rels.some(ds => ds.serverId == s.id));
        };
        const serversNotInDomain = (domainId) => {
            const inDomain = getServersOfDomain(domainId).map(s => s.id);
            return servers.value.filter(s => !inDomain.includes(s.id));
        };
        const addServerToDomain = async (domainId) => {
            const sid = selectedServer[domainId];
            if (!sid) return;
            await axios.post('/domainservers', { domainId, serverId: sid });
            selectedServer[domainId] = '';
            await fetchAll();
        };
        const removeServerFromDomain = async (domainId, serverId) => {
            await axios.delete(`/domainservers/${domainId}_${serverId}`);
            await fetchAll();
        };

        fetchAll();
        return {
            isLoggedIn, userInfo, showLoginModal, authForm, authLoading, authError,
            doLogin, logout,
            menu, domains, servers, domainServers,
            newDomain, newServer, selectedServer,
            addDomainDialog,
            editDomain, deleteDomain,
            addServerDialog,
            editServer, deleteServer,
            getServersOfDomain, serversNotInDomain,
            addServerToDomain, removeServerFromDomain,
            showAddServerDialog,
            showPassword,
            editDomainDialog, linkedServers, unlinkedServers, selectedLeft, selectedRight,
            editDomain, selectLeft, selectRight, addServerToDomainEdit, removeServerFromDomainEdit,
            showAddDomainDialog,
            editServerDialog,
            saveEditServer
        };
    }
}).mount('#app');
</script>
</body>
</html> 